#!/usr/bin/env python

import sys
import re
import os
import ConfigParser
#from logger import logfile
from logger import *


class Config(ConfigParser.ConfigParser):
    def __init__(self,defaults=None,configfile='puttyknife.ini', logfile=logfile):
        # self.sections=[None]
        self.logfile=logfile
        self.valid_settings={'profile':
                                {'string':
                                      ['server',
                                       'username',
                                       'password',
                                       'keyfile',
                                       'proxy host',
                                       'proxy method',
                                       'proxy username',
                                       'proxy password',
                                       'proxy command',
                                       'logfile',
                                       ],
                                 'integer':
                                      ['port',
                                       'retry delay',
                                       'ssh version',
                                       'socks port',
                                       'proxy port',
                                       ],
                                 'boolean':
                                      ['compression',
                                       'verbose',
                                       'forward x11',
                                       'forward agent',
                                       'disable pty',
                                       'private key',
                                       'dynamic forward',
                                       'log to file',
                                       'auto reconnect',
                                       ]
                                },
                              'tunnel':
                                {'string':
                                    ['source address',
                                     'destination address',
                                     'forward type',
                                     'service desc',
                                    ],
                                  'integer':
                                    ['source port',
                                     'destination port',
                                    ],
                                },
                              'global':
                                {'string':
                                    ['default profile',
                                    ],
                                 'boolean':
                                    ['auto connect',
                                    ]
                                }
                            }
        self.default_settings={'profile': 
                                    {'server': None,
                                     'username': None,
                                     'password': None, 
                                     'keyfile': None,
                                     'logfile': None,
                                     'log to file': False,
                                     'port':22,
                                     'use socks port': False,
                                     'socks port': 7070,
                                     'retry delay':10,
                                     'ssh version':0,
                                     'compression':False,
                                     'verbose':False,
                                     'forward x11':False,
                                     'forward agent':False,
                                     'disable pty':True,
                                     'private key':False,
                                     'dynamic forward':True,
                                     'log to file':False,
                                     'proxy method': None,
                                     'proxy host': None,
                                     'proxy port': -1,
                                     'proxy username': None,
                                     'proxy password': None,
                                     'proxy command': 'connect %host %port\n',
                                     'auto reconnect': False,
                                    },
                                    'tunnel':
                                        {'source address':'127.0.0.1',
                                           'source port':-1,
                                           'destination address':None,
                                           'destination port':-1,
                                           'forward type':None
                                        },
                                    'global':
                                        {'auto connect': False,
                                         'default profile': None,
                                        }
                                }
        self.required_settings={'profile':
                                    ['hostname', 
                                    ]
                                }
        self.setting={}
        self.profiles=[]
        if hasattr(configfile,'name'):
            self.rcfile=configfile
            self.filename=self.rcfile.name
        else:
            self.filename=os.path.expanduser(configfile)
            self.rcfile=self.__open(self.filename)
        ConfigParser.ConfigParser.__init__(self,defaults)
        try:
            self.read()
        except ConfigParser.ParsingError, (error):
            self.logfile.write('Error parsing %s' % self.filename,
                          level=level.ERROR)
            self.logfile.flush()
            retval=False
        return 

    def __open(self,filename):
        try:
            os.stat(filename)
        except:
            self.logfile.write("Creating config file %s" % self.filename)
            self.logfile.flush()
            try:
                f=open(filename,'w')
                f.close()
            except (IOError, os.error), why:
                self.logfile.write('Error creating %s' % filename,
                              level=level.ERROR)
                sys.exit(-1)
        try:
            rcfile=open(filename)
        except (IOError, os.error), why:
            self.logfile.write('Error reading from %s ' % filename,
                          level=level.ERROR)
            self.logfile.flush()
            sys.exit(-1)
        return rcfile
                        
    def __has_required(self):
        retval=True
        self.missing_sections=[]
        self.missing_settings={}
        for section in self.sections():
            try:
                for setting in self.required_settings[section]:
                    if not self.has_option(section, setting):
                        self.missing_settings[section]=setting
                        retval=False
            except KeyError:
                retval=False
        return retval
        
    def read(self):
        logfile.write('Loading configuration from %s' % self.filename, 
                      level.INFO)
        self.readfp(self.rcfile,self.filename)
        if not self.__has_required():
            if self.missing_sections:
                msg='File %s has missing section(s): %s' % (self.filename, 
                                                            self.missing_sections)
                self.logfile.write(msg,level=level.ERROR)
                # raise ConfigParser.ParsingError,msg
            if self.missing_settings:
                msg='File %s has missing setting(s): %s' % (self.filename,
                                                            self.missing_settings)
                self.logfile.write(msg,level=level.ERROR)
                # raise ConfigParser.ParsingError,msg
        tunnel=re.compile('^.*\:tunnel \#\d{1,3}$')
        if not self.has_section('global'):
            self.add_section('global')
        sections=self.sections()
        sections.sort()
        for section in sections:
            try:
                if section == 'global':
                    sectiontype='global'
                elif tunnel.match(section):
                    sectiontype='tunnel'
                else:
                    sectiontype='profile'
            except TypeError:
                sectiontype='profile'
            if sectiontype == 'profile':
                self.profiles.append(section)
            for type in self.valid_settings[sectiontype].keys():
                for setting in self.valid_settings[sectiontype][type]:
                    key='%s.%s' % (section,setting)
                    if self.has_option(section, setting):
                        if type == 'string':
                            value=self.get(section,setting)
                            if value == 'None':
                                value=None
                            self.setting[key]=value                                
                        elif type == 'integer':
                            try:
                                value=self.get(section,setting)
                                self.setting[key]=int(value)
                            except ValueError: 
                                s='Invalid value for setting "%s", "%s" in "%s"' \
                                    % (value,setting,section)
                                self.logfile.write(s,level=level.ERROR)
                                raise ConfigParser.ParsingError,s
                        elif type == 'float':
                            self.setting[key]= float(self.get(section,setting))
                        elif type == 'boolean':
                            self.setting[key]=\
                                (self.get(section,setting) == '1') or \
                                (self.get(section,setting).lower() == 'on') or \
                                (self.get(section,setting).lower() == 'true')
                    else:
                        self.setting[key]=self.default_settings[sectiontype][setting]

    def write(self,newfilename=None):
        logfile.write('Writing config %s' % self.filename,
                      level=level.DEBUG)
        logfile.flush()
        if not newfilename:
            filename=self.filename
        else:
            filename=newfilename
            self.filename=newfilename
        keys=self.setting.keys()
        keys.sort()
        for key in keys:
            section,setting=key.split('.')
            if self.has_section(section):
                self.set(section,setting,'%s' % (self.setting[key]))
        self.rcfile.close()
        try:
            f=open(filename,'w')
        except (IOError,os.error), why:
            self.logfile.write("Error writing to %s %s" % (filename,why),
                          level=level.ERROR)
        ConfigParser.ConfigParser.write(self,f)
        f.close()
        self.rcfile = self.__open(self.filename)
        self.logfile.write('Wrote config %s' % self.filename,
                      level=level.DEBUG)
        self.logfile.flush()

    def new_profile(self,profilename=None):
        if profilename:
           self.add_section(profilename)
           self.profiles.append(profilename)
        for setting in self.default_settings['profile']:
            self.set(profilename,setting, 
                '%s' % self.default_settings['profile'][setting])
            key='%s.%s' % (profilename,setting)
            self.setting[key] = \
                self.default_settings['profile'][setting]
                
    def new_tunnel(self,profile,tunnel_num):
        tunnel_section = "%s:tunnel #%s" % (profile,tunnel_num)
        self.add_section(tunnel_section)
        for setting in self.default_settings['tunnel']:
            self.set(tunnel_section, setting,
                     "%s" % self.default_settings['tunnel'][setting])
            key='%s.%s' % (tunnel_section, setting)
            self.setting[key] = \
                self.default_settings['tunnel'][setting]
        return tunnel_section
                
    def get_tunnels(self,profile):
        tunnels=[]
        tunnel=re.compile('^%s.*\:tunnel \#\d{1,3}$' % profile)
        for section in self.sections():
            if tunnel.match(section):
                tunnels.append(section)
        return tunnels
    
    def clear_tunnels(self, profile):
        tunnels=self.get_tunnels(profile)
        for tunnel in tunnels:
            self.remove_section(tunnel)
                
config=Config()        
# Unit test
if __name__ == '__main__':
    config=Config()
    print config.setting
    for key in config.setting.keys():
        print "%s = %s" % (key,config.setting[key])
    config.write('portal-test.conf')
    logfile.write('test')



                        
            
